#ifndef INSTRUCTION_H
#define INSTRUCTION_H

#include "Types.h"

/// @brief Clear interrupt flag. 0 means interrupt is disable
static inline void Cli()
{
    __asm__ __volatile__("cli");
}

/// @brief Set interrupt flag. 1 means interrupt is enable
static inline void Sti()
{
    __asm__ __volatile__("sti");
}

static inline void Hlt()
{
    __asm__ __volatile__("hlt");
}


// 从端口寄存器上读取数值
static inline uint8_t Inb(uint16_t port)
{
    // inb port，value
    uint8_t value;
    // :传出数据  :传入数据
    // inb要求端口号必须在dx寄存器中，输出结果必须写入ax寄存器
    __asm__ __volatile__("inb %[p], %[v]" : [v]"=a"(value) : [p]"d"(port));
    return value;
}

// 向着指定端口写入一个数据
static inline void Outb(uint16_t port, uint8_t value)
{
    // outb要求端口号必须在dx寄存器中，输出结果必须写入ax寄存器
    __asm__ __volatile__("outb %[v], %[p]" :: [v]"a"(value), [p]"d"(port));
}

/// @brief 从指定端口读取16位数据
/// @param port 
static inline uint16_t Inw(uint16_t port)
{
    uint16_t value;
    __asm__ __volatile__("inw %[p], %[v]" : [v]"=a"(value) : [p]"dN"(port));
    return value;
}



// 加载lgdt，start是lgdt表的地址，size是lgdt表的大小
static inline void Lgdt(uint32_t start, uint32_t size)
{
    struct {
        uint16_t size;
        uint16_t startL;
        uint16_t startH;
    } gdtPtr;
    gdtPtr.size = size - 1;
    gdtPtr.startL = start & 0xFFFF;
    gdtPtr.startH = start >> 16;  
    // lgdt只能从内存加载gdt表的信息
    __asm__ __volatile__("lgdt %[p]" :: [p]"m"(gdtPtr));
}


static inline void Lidt(uint32_t start, uint32_t size)
{
    struct {
        uint16_t size;
        uint16_t startL;
        uint16_t startH;
    } idtPtr;
    idtPtr.size = size - 1;
    idtPtr.startL = start & 0xFFFF;
    idtPtr.startH = start >> 16;  
    // lidt只能从内存加载idt表的信息
    __asm__ __volatile__("lidt %[p]" :: [p]"m"(idtPtr));
}


/**
 * @brief 读取 CR0 寄存器内容
 * @return 当前 CR0 的值
 * 
 * CR0 是最重要的控制寄存器之一，包含：
 * - PE（Protection Enable）：保护模式启用标志
 * - PG（Paging）：分页开启标志
 */
static inline uint32_t ReadCr0()
{
    uint32_t cr0;
    __asm__ __volatile__("mov %%cr0, %[v]" : [v]"=r"(cr0));
    return cr0;
}

/// @brief 写入cr0寄存器
/// @param cr0 
static inline void WriteCr0(uint32_t value)
{
    __asm__ __volatile__("mov %[v], %%cr0" :: [v]"r"(value));
}

static inline int ReadCr2()
{
    uint32_t cr2;
    __asm__ __volatile__("mov %%cr2, %[v]" : [v]"=r"(cr2));
    return cr2;
}


static inline int ReadCr3()
{
    uint32_t cr3;
    __asm__ __volatile__("mov %%cr3, %[v]" : [v]"=r"(cr3));
    return cr3;
}

static inline void WriteCr3(uint32_t value)
{
    __asm__ __volatile__("mov %[v], %%cr3" :: [v]"r"(value));
}

static inline uint32_t ReadCr4()
{
    uint32_t cr4;
    __asm__ __volatile__("mov %%cr4, %[v]" : [v]"=r"(cr4));
    return cr4;
}

static inline void WriteCr4(uint32_t value)
{
    __asm__ __volatile__("mov %[v], %%cr4" :: [v]"r"(value));
}

/**
 * @brief 执行远跳转（段选择子 + 偏移）
 * @param selector 目标代码段选择子
 * @param offset   段内偏移地址
 * 
 * 使用 ljmp 指令进行跨段跳转，常用于切换特权级、进入保护模式等场景
 */
static inline void FarJump(uint32_t selector, uint32_t offset)
{
    uint32_t temp[] = {offset, selector};
    // temp = v，v存的是temp的地址，然后*(v)取地址中的值
    __asm__ __volatile__("ljmpl *(%[v])" :: [v]"r"(temp));
}

/// @brief Read data from eflags register
/// @return 
static inline uint32_t ReadEFLAGS()
{
    uint32_t value;
    // Pop eflags to stack
    // Pop top of the stack to eax
    // 
    __asm__ __volatile__("pushfl\n\t popl %%eax" : "=a"(value));
    return value;
}

/// @brief Write data to eflags register
/// @param value 
static inline void WriteEFLags(uint32_t value)
{
    __asm__ __volatile__("pushl %%eax\n\tpopfl" :: "a"(value));
}


static inline void WriteTR(uint32_t tssSelector)
{
    // Load task register
    // In GCC inline assembly, 
    // the "a"(tssSelector) constraint will automatically place the lower 16 bits of tssSelector into the ax register, 
    // even if you pass a 32-bit variable.
    __asm__ __volatile__("ltr %%ax" :: "a"(tssSelector));
}


#endif